package ch.fusun.baron.turn;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;

import ch.fusun.baron.core.injection.ReInjector;

/**
 * Registry for all the turn task
 */
@SuppressWarnings("rawtypes")
public class TurnRegistry {

	private static final String DEPENDS_ON = "dependsOn"; //$NON-NLS-1$
	private static final String DEPENDENCY = "dependency"; //$NON-NLS-1$
	private static final String TURNTASK_ID = "ch.fusun.baron.turn"; //$NON-NLS-1$
	private static final String TURNTASK = "turntask"; //$NON-NLS-1$
	private static TurnRegistry instance;
	private List<TurnTask> turnTasks;
	private final Map<TurnTask, List> turnDependencies;

	/**
	 * Loads all available turn tasks
	 */
	@SuppressWarnings("unchecked")
	public TurnRegistry() {
		turnTasks = new ArrayList<TurnTask>();
		turnDependencies = new HashMap<TurnTask, List>();
		IConfigurationElement[] config = Platform.getExtensionRegistry()
				.getConfigurationElementsFor(TURNTASK_ID);
		try {
			for (IConfigurationElement e : config) {
				TurnTask bean = (TurnTask) e
						.createExecutableExtension(TURNTASK);
				ReInjector.getInstance().reInject(bean);
				turnTasks.add(bean);
				List dependencies = new LinkedList();
				for (IConfigurationElement child : e.getChildren(DEPENDENCY)) {
					dependencies.add(child
							.createExecutableExtension(DEPENDS_ON).getClass());
				}
				turnDependencies.put(bean, dependencies);
			}
		} catch (CoreException ex) {
			System.err.println("Handle this error with log or so: " //$NON-NLS-1$
					+ ex.getMessage());
		}
		turnTasks = orderByDependency(turnTasks);
	}

	private List<TurnTask> orderByDependency(List<TurnTask> original) {
		List<TurnTask> result = new LinkedList<TurnTask>();
		int i = 0;
		while (original.size() > 0) {
			i = (i + 1) % original.size();
			TurnTask turntask = original.get(i);
			List dependencies = turnDependencies.get(turntask);
			if (dependencies == null || dependencies.isEmpty()
					|| containsAllClasses(result, dependencies)) {
				original.remove(turntask);
				result.add(turntask);
			}
		}
		return result;
	}

	private static boolean containsAllClasses(List<TurnTask> list,
			List dependencies) {
		for (Object dep : dependencies) {
			boolean ok = false;
			for (TurnTask task : list) {
				if (task.getClass().equals(dep)) {
					ok = true;
					break;
				}
			}
			if (!ok) {
				return false;
			}
		}
		return true;
	}

	/**
	 * @return The singleton instance
	 */
	public static TurnRegistry getInstance() {
		if (instance == null) {
			instance = new TurnRegistry();
		}
		return instance;
	}

	/**
	 * @return All available turn tasks
	 */
	public List<TurnTask> getTurnTasks() {
		return turnTasks;
	}

}
